package com.constructiveproof.example.auth.strategies

import org.scalatra.{Cookie, CookieOptions, ScalatraBase}
import org.scalatra.auth.ScentryStrategy
import com.constructiveproof.example.models.User
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
import org.slf4j.LoggerFactory

class RememberMeStrategy(protected val app: ScalatraBase)(implicit request: HttpServletRequest, response: HttpServletResponse)
  extends ScentryStrategy[User] {

  val logger = LoggerFactory.getLogger(getClass)

  //定义策略名
  override def name: String = "RememberMe"

  val COOKIE_KEY = "rememberMe"
  private val oneWeek = 7 * 24 * 3600

  /***
    * Grab the value of the rememberMe cookie token.
    * 抓取记住我cookie的token的值。
    * 如果存在就返回字符串
    * 否则返回空字符串
    */
  private def tokenVal = {
    app.cookies.get(COOKIE_KEY) match {
      case Some(token) => token
      case None => ""
    }
  }

  /***
    * 确定当前策略是否应为当前请求运行
    * 是数据检验
    */
  override def isValid(implicit request: HttpServletRequest):Boolean = {
    logger.info("RememberMe策略: 是否要执行（根据token值是否存在）: " + (tokenVal != "").toString())
    tokenVal != ""
  }

  /***
    * 在真实的项目中，我们会检查cookie的令牌值是否和储存在数据库中（或缓存中）已知哈希，看看是否要接受。
    * 在测试中以一个固定字符串代替
    */
  def authenticate()(implicit request: HttpServletRequest, response: HttpServletResponse) = {
    logger.info("RememberMe策略: 正在尝试验证（token）")
    if(tokenVal == "foobar") Some(User("foo"))
    else None
  }
  
  /**
    * 如果用户目前没有验证，应该发生什么？
    * 也就是说，用户未登陆，一般跳转到登陆页面
    */
  override def unauthenticated()(implicit request: HttpServletRequest, response: HttpServletResponse) {
    app.redirect("/sessions/new")
  }

  /***
    *
    * 在认证成功后执行；
    * if(在本策略认证成功||(在验证密码认证成功&&勾选了记住我)){
    *   设定记住登录状态的cookies，写回客户端
    * }
    *
    */
  override def afterAuthenticate(winningStrategy: String, user: User)(implicit request: HttpServletRequest, response: HttpServletResponse) = {
    logger.info("在认证成功后执行，保持登录状态的token")
    if (winningStrategy == "RememberMe" ||
      (winningStrategy == "UserPassword" && checkbox2boolean(app.params.get("rememberMe").getOrElse("").toString))) {

      val token = "foobar"
      app.cookies.set(COOKIE_KEY, token)(CookieOptions(maxAge = oneWeek, path = "/"))
    }
  }

  /**
    * 在之前注销运行此代码，清理任何遗留数据库状态和删除Cookie记得登录状态的token。
   */
  override def beforeLogout(user: User)(implicit request: HttpServletRequest, response: HttpServletResponse) = {
    logger.info("rememberMe: beforeLogout")
    if (user != null){
      user.forgetMe
    }
    app.cookies.delete(COOKIE_KEY)(CookieOptions(path = "/"))
  }


  /**
   * 用于容易地匹配一个复选框的值
   */
  private def checkbox2boolean(s: String): Boolean = {
    s match {
      case "yes" => true
      case "y" => true
      case "1" => true
      case "true" => true
      case _ => false
    }
  }
}

